import React, {
  forwardRef,
  useState,
  useEffect,
  useMemo,
  useImperativeHandle,
  useRef,
} from 'react';
import _ from 'lodash';
import { Spin } from 'antd';
import SearchBar from '@/components/CommonSearchBar';
import HeaderTools from './components/tableHeaderTools';
import HeaderButtons from './components/tableHeaderButtons';
import TableContent from './components/tableContent';
import {
  getPaging,
  getDefaultSize,
  getHeaderOptions,
  getDefaultSelection,
  getDefaultColumnSettings,
  formatColumnChildrenFixed,
} from './tools';
import { getUsefulSearchItems } from '@/components/CommonSearchBar/tools';
import styles from './index.less';

/**
 * rowKey: string | func; // 数据的唯一id
 * extraParams?: {}; 额外的入参
 * columns: {
 *   title: string;
 *   dataIndex: string;
 *   width?: number; // 列宽度， 未设置则平分计算剩余宽度，计算值最小取160。（建议至少保留一列或一列以上不设置宽度）
 *   fixed?: bool | "left" | "right"; // 列的固定规则 true === "left"，默认不固定
 *   align?: "left" | "right" | "center"; // 左右对其方式, 默认"center"
 *   columnControl?: {
 *     typeList?: string | string[]; // 列操作配置类型，支持"search" | "filter" | "sorter" | "transfer"；（注："search"和"filter"只能同时存在一个，若都存在，优先"search", "transfer"只转译展示）
 *     filterOptions?: {text: string; value: string}[]; // 列"filter"操作所需要的选项。（同步：优先取filterOptions选项）
 *     filterDictType?: string; // 列"filter"操作所需要的字典选项值（异步：配置字典类型key）
 *   }; // 列操作配置规则（注：若同时存在search配置，则尽量避免同一字段的重复逻辑，重复情况下优先以search为准
 *   customRender?: func; // 自定义渲染
 * }[]; // 列定义
 * request: async func; // 数据请求 params => ({data: {}[], count?: number}); 分页情况下需返回count
 * search?: {}[]; // 顶部搜索配置, 配置规则同"@/components/CommonSearchBar"
 * header?: string | {
 *   headerTitle?: string; // 表格标题
 *   headerToolsRender?: bool; // 是否渲染
 *   headerButtonList?: {
 *    key: string;
 *    label: string;
 *    icon?: node;
 *    ghost?: bool;
 *    danger?: bool;
 *    type?: "primary" | undefined
 *    confirmText?: string;
 *    loading?: bool;
 *    disabled?: bool;
 *   }[]; // 按钮属性
 *   headerButtonClick?: func; // 按钮点击事件, (args: {key}) => {}
 * }; // 表头配置 （string格式为表格标题，object格式为详细内容配置）
 * paging?: bool | {size: number}; // 是否分页，默认分页(10条1页)
 * tableSize?: "default" | "middle" | "small"; // 表格尺寸
 * indexRender?: bool; // 是否渲染序号列, 默认不渲染序号列
 * initializationData?: bool; // 是否首次初始化数据；默认初始化请求数据
 * rowSelection?: bool | {
 *   checkStrictly?: bool; // 默认true
 *   getCheckboxProps?: func; // 设置checkbox属性
 * }; // 是否开启选择，默认不开启
 * */

export default forwardRef(
  (
    {
      rowKey,
      header,
      indexRender,
      rowSelection,
      paging = true,
      extraParams = {},
      tableSize = 'middle',
      initializationData = true,
      search,
      columns,
      request,
    },
    ref,
  ) => {
    const searchRef = useRef(null);
    const tableRef = useRef(null);
    // 格式化
    const headerOptions = useMemo(() => getHeaderOptions(header), [header]);
    const searchFormItems = useMemo(() => getUsefulSearchItems(search), []);
    const defaultTableSize = useMemo(() => getDefaultSize(tableSize), []);
    const { isSelection, getCheckboxProps, checkStrictly } = useMemo(
      () => getDefaultSelection(rowSelection),
      [],
    );
    const { defaultColumns, defaultColumnSettings } = useMemo(
      () => getDefaultColumnSettings(columns, indexRender, searchFormItems),
      [columns],
    );
    const defaultPagingOpts = useMemo(() => getPaging(paging), []);
    const isPaging = defaultPagingOpts.size !== -1;
    const isHeaderRender = !_.isEmpty(headerOptions);
    const { headerTitle, isHeaderToolsRender, headerButtons, headerButtonClick } = headerOptions;

    // 表格数据
    const [params, setParams] = useState({});
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState([]);
    const [count, setCount] = useState(0);
    const [selectedList, setSelectedList] = useState([]);
    // 工具栏
    const [size, setSize] = useState(defaultTableSize);
    const [columnSettings, setColumnSettings] = useState(defaultColumnSettings);
    // 表格列设置处理(暂不支持级联节点排序)
    const columnsWithFormat = useMemo(() => {
      const { leftColumns, middleColumns, rightColumns } = columnSettings;
      const nextSortList = _.filter(
        [
          ..._.map(leftColumns, ({ key, checked }) => ({ key, fixed: 'left', checked })),
          ..._.map(middleColumns, ({ key, checked }) => ({ key, fixed: false, checked })),
          ..._.map(rightColumns, ({ key, checked }) => ({ key, fixed: 'right', checked })),
        ],
        ({ checked }) => !!checked,
      );
      const nextColumns = [];
      _.forEach(nextSortList, ({ key, fixed }) => {
        const columnItem = _.find(defaultColumns, ({ key: itemKey }) => itemKey === key);
        if (columnItem) {
          if (columnItem.key === 'index') {
            nextColumns.push(
              _.assign({}, columnItem, {
                fixed,
                render: (text, item, index) =>
                  isPaging
                    ? (params.size || 0) * ((params.current || 1) - 1) + index + 1
                    : index + 1,
              }),
            );
          } else {
            nextColumns.push(formatColumnChildrenFixed(columnItem, fixed));
          }
        }
      });
      return nextColumns;
    }, [columns, params, columnSettings]);

    // 发起请求
    const fetchData = async (params) => {
      try {
        const { data, count } = await request(
          _.assign({}, _.isPlainObject(extraParams) ? extraParams : {}, params),
        );
        const currentData = _.isArray(data) ? data : [];
        const currentCount = isPaging && /^\d+$/.test(count) ? parseInt(count) : currentData.length;
        setData(currentData);
        setCount(currentCount);
        setSelectedList([]);
      } catch (e) {
        setData([]);
        setCount(0);
        setSelectedList([]);
      }
    };
    const handleRequest = (params) => {
      fetchData(params).then(() => {
        setLoading(false);
      });
    };

    // 初始化
    useEffect(() => {
      const init = async () => {
        const defaultParams = _.assign({}, defaultPagingOpts);
        if (!!searchFormItems.length) {
          const { getInitialSearchParams } = searchRef.current || {};
          if (getInitialSearchParams) {
            try {
              const params = await getInitialSearchParams();
              _.assign(defaultParams, params ? { params: _.sortBy(params, 'column') } : null);
            } catch (e) {
              console.log('获取初始查询条件校验不通过');
            }
          }
        }
        setParams(defaultParams);
        if (request) {
          if (!!initializationData) {
            // 初始化数据
            return handleRequest(defaultParams);
          }
        }
        setLoading(false);
      };

      init().then(() => {
        console.log('初始化结束');
      });
    }, []);

    // 刷新
    const handleRefresh = () => {
      if (request) {
        setLoading(true);
        setParams((currentParams) => {
          handleRequest(currentParams);
          return currentParams;
        });
      }
    };

    // 搜索
    const handleSearch = (params = []) => {
      if (request) {
        setLoading(true);
        const { resetTableColumnControl } = tableRef.current || {};
        resetTableColumnControl && resetTableColumnControl();
        setParams((prevParams) => {
          const nextParams = _.assign(
            {},
            prevParams,
            { params: _.sortBy(params, 'column') },
            isPaging ? { current: 1 } : null,
          );
          handleRequest(nextParams);
          return nextParams;
        });
      }
    };

    // 表头或分页搜索
    const handleTableSearch = (params) => {
      if (request) {
        setParams(params);
        setLoading(true);
        handleRequest(params);
      }
    };

    // 方法挂载
    useImperativeHandle(ref, () => ({
      refresh: handleRefresh,
      getSelectedList: () => {
        const selectedItems = [];
        const getKeyVal = (item) => {
          if (typeof rowKey === 'function') {
            return rowKey(item);
          } else if (_.isString(rowKey)) {
            return item[rowKey];
          }
        };
        const loop = (list) => {
          if (list && list.length) {
            _.forEach(list, (item) => {
              const keyVal = getKeyVal(item);
              const { children, ...restObj } = item;
              if (_.includes(selectedList, keyVal)) {
                selectedItems.push(restObj);
              }
              loop(children);
            });
          }
        };
        loop(data);
        return selectedItems;
      },
    }));

    return (
      <>
        {!!searchFormItems.length && (
          <SearchBar
            ref={searchRef}
            searchLoading={loading}
            formList={searchFormItems}
            onSearch={handleSearch}
          />
        )}
        <div className={styles.tableContainer}>
          <Spin spinning={loading} tip="加载中..">
            {/** title header */}
            {isHeaderRender ? (
              <div className={styles.tableToolsContainer}>
                <div className={styles.tableToolsHeader}>
                  <span className={styles.tableToolsHeaderText}>{headerTitle || ''}</span>
                </div>
                <div className={styles.tableToolsContent}>
                  <div className={styles.tableToolsContentRestItem}>
                    {!_.isEmpty(headerButtons) && (
                      <HeaderButtons buttonList={headerButtons} onClick={headerButtonClick} />
                    )}
                  </div>
                  {isHeaderToolsRender && (
                    <div className={styles.tableToolsContentFixedItem}>
                      <HeaderTools
                        loading={loading}
                        tableSize={size}
                        setTableSize={setSize}
                        columnSettings={columnSettings}
                        setColumnSettings={setColumnSettings}
                        handleRefresh={handleRefresh}
                      />
                    </div>
                  )}
                </div>
              </div>
            ) : (
              <div className={styles.tableHeaderPlaceholder} />
            )}
            {/** title content */}
            <TableContent
              ref={tableRef}
              size={size}
              data={data}
              rowKey={rowKey}
              columns={columnsWithFormat}
              columnComposeParams={params.params || []}
              pagination={
                isPaging
                  ? {
                      total: count,
                      current: params.current || 1,
                      pageSize: params.size || defaultPagingOpts.size,
                    }
                  : null
              }
              rowSelection={
                isSelection
                  ? {
                      checkStrictly,
                      getCheckboxProps,
                      selectedRowKeys: selectedList,
                      onChange: (keys) => {
                        setSelectedList(keys);
                      },
                    }
                  : null
              }
              handleSearch={handleTableSearch}
            />
          </Spin>
        </div>
      </>
    );
  },
);
